home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir24 / psi110g.zip / INDEX.C < prev    next >
C/C++ Source or Header  |  1994-07-05  |  29KB  |  1,110 lines

  1. /* Mail Index File routines for JNOS and others.
  2.  * (C) 1993, Johan. K. Reinalda, WG7J/PA3DIS
  3.  * Free for non-commercial use if this notice is retained.
  4.  *
  5.  * You should be able to patch this into you mailer program easily.
  6.  * There are two public functions.
  7.  *
  8.  * int MsgsInMbx(char *name);
  9.  *      this routine returns the number of messages in a mailbox.
  10.  *
  11.  *      Calling convention:
  12.  *      'char *name' is the name of the mailbox, in 'directory format'.
  13.  *      this means that subdirectories should be represented by '/'
  14.  *      characters, and not '.' or '\' . Also, the '.txt' extension
  15.  *      should not be used !
  16.  *
  17.  *      Return value:
  18.  *      It will return -1 if it detects an error in the index file.
  19.  *      Otherwise the number of messages will be returned.
  20.  *
  21.  *      Use:
  22.  *      JNOS uses it to dynamically size the structure that tracks messages.
  23.  *
  24.  * int IndexFile(char *name,int verbose);
  25.  *      This routines creates an index file for the mailbox given.
  26.  *
  27.  *      Calling convention:
  28.  *      'char *name'
  29.  *      'char *name' is the name of the mailbox, in 'directory format'.
  30.  *      this means that subdirectories should be represented by '/'
  31.  *      characters, and not '.' or '\' . Also, the '.txt' extension
  32.  *      should not be used ! The 'mailspool' directory will be pre-pended,
  33.  *      and should not be included in the mailbox name. Eg. the file
  34.  *      '/spool/mail/users/johan.txt' should be indexed as 'users/johan'
  35.  *
  36.  *      'int verbose'
  37.  *      if set, the index will be printed before it is written.
  38.  *
  39.  *      Return values:
  40.  *      0  if no error occured
  41.  *      -2 if it can not open the mailbox for reading binary mode
  42.  *      -3 if it can not open the index file for writing
  43.  *      -10 on other errors
  44.  *
  45.  *      Notes:
  46.  *      -you should make sure the mailbox file is properly locked before
  47.  *       calling this routine.
  48.  *
  49.  *      -you need to provide the following variables:
  50.  *       char *Mailspool, should be "/spool/mail"
  51.  *       char *Arealist, should be "/spool/areas"
  52.  *
  53.  *      -you also need to provide a dummy function pwait() in your sources,
  54.  *       to avoid getting an unknown function error when linking.
  55.  *       void pwait(void *p) {};
  56.  *       should do it...
  57.  */
  58. #ifdef MSDOS
  59. #include <io.h>
  60. #endif
  61. #include <fcntl.h>
  62. #include <sys/stat.h>
  63. #include <ctype.h>
  64. #include <time.h>
  65. #include <string.h>
  66. #ifdef MSDOS
  67. #include <dir.h>
  68. #include <dos.h>
  69. #endif
  70. #include "global.h"
  71. #include "socket.h"
  72. #include "index.h"
  73. #include "mailutil.h"
  74. #include "mailbox.h"
  75. #include "smtp.h"
  76. #include "files.h"
  77. #include "bm.h"
  78.   
  79. #ifdef MAIL2IND
  80. #undef fopen
  81. #define tprintf printf
  82. #define tputc putchar
  83. #endif
  84.   
  85. /* return the number of messages in a given mailbox.
  86.  * name needs to be in directory format.
  87.  * Returns:
  88.  * -1 if index file is corrupt,
  89.  *  otherwize the number of messages in the mailbox
  90.  */
  91. int MsgsInMbx(char *name) {
  92.     int ind;
  93.     struct indexhdr hdr;
  94.     char buf[FILE_PATH_SIZE];
  95.   
  96.     sprintf(buf,"%s/%s.ind",Mailspool,name);
  97.     if((ind = open(buf,READBINARY)) == -1)
  98.         return 0;
  99.   
  100.     /* Read the header */
  101.     if(read_header(ind,&hdr) == -1)
  102.         hdr.msgs = 0;
  103.   
  104.     close(ind);
  105.     return hdr.msgs;
  106. }
  107.   
  108. /* replace terminating end of line marker(s) with null */
  109. void
  110. rip(s)
  111. register char *s;
  112. {
  113.     register char *cp;
  114.   
  115.     if((cp = strchr(s,'\n')) != NULLCHAR)
  116.         *cp = '\0';
  117. }
  118.   
  119. char *skipwhite(char *cp) {
  120.   
  121.     while((*cp != '\0') && (*cp == ' ' || *cp == '\t'))
  122.         cp++;
  123.     return cp;
  124. }
  125.   
  126. /* Given a string of the form <user@host>, extract the part inside the
  127.  * angle brackets and return a pointer to it.
  128.  */
  129. char *
  130. getname(cp)
  131. char *cp;
  132. {
  133.     char *cp1;
  134.   
  135.     if ((cp = strchr(cp,'<')) == NULLCHAR)
  136.         return NULLCHAR;
  137.     cp++;   /* cp -> first char of name */
  138.     cp = skipwhite(cp);
  139.     if((cp1 = strchr(cp,'>')) == NULLCHAR)
  140.         return NULLCHAR;
  141.     *cp1 = '\0';
  142.     return cp;
  143. }
  144.   
  145. /* Parse a string in the "Text: Text <user@host>" or "Text: user@host (Text)"
  146.  * formats for the address user@host.
  147.  */
  148. char *
  149. getaddress(string,cont)
  150. char *string;
  151. int cont;       /* true if string is a continued header line */
  152. {
  153.     char *cp, *ap = NULLCHAR;
  154.     int par = 0;
  155.   
  156.     if((cp = getname(string)) != NULLCHAR) /* Look for <> style address */
  157.         return cp;
  158.   
  159.     cp = string;
  160.     if(!cont)
  161.         if((cp = strchr(string,':')) == NULLCHAR)   /* Skip the token */
  162.             return NULLCHAR;
  163.         else
  164.             ++cp;
  165.     for(; *cp != '\0'; ++cp) {
  166.         if(par && *cp == ')') {
  167.             --par;
  168.             continue;
  169.         }
  170.         if(*cp == '(')      /* Ignore text within parenthesis */
  171.             ++par;
  172.         if(par)
  173.             continue;
  174.         if(*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == ',') {
  175.             if(ap != NULLCHAR)
  176.                 break;
  177.             continue;
  178.         }
  179.         if(ap == NULLCHAR)
  180.             ap = cp;
  181.     }
  182.     *cp = '\0';
  183.     return ap;
  184. }
  185.   
  186. char *Months[12] = { "Jan","Feb","Mar","Apr","May","Jun",
  187. "Jul","Aug","Sep","Oct","Nov","Dec" };
  188.   
  189. char *Hdrs[] = {
  190.     "Approved: ",
  191.     "From: ",
  192.     "To: ",
  193.     "Date: ",
  194.     "Message-Id: ",
  195.     "Subject: ",
  196.     "Received: ",
  197.     "Sender: ",
  198.     "Reply-To: ",
  199.     "Status: ",
  200.     "X-BBS-Msg-Type: ",
  201.     "X-Forwarded-To: ",
  202.     "Cc: ",
  203.     "Return-Receipt-To: ",
  204.     "Apparently-To: ",
  205.     "Errors-To: ",
  206.     "Organization: ",
  207.     "Newsgroups: ",
  208.     "Path: ",
  209.     "X-BBS-Hold: ",
  210.     NULLCHAR,
  211. };
  212.   
  213.   
  214. /* return the header type */
  215. int
  216. htype(s)
  217. char *s;
  218. {
  219.     register char *p;
  220.     register int i;
  221.   
  222.     p = s;
  223.     /* check to see if there is a ':' before and white space */
  224.     while (*p != '\0' && *p != ' ' && *p != ':')
  225.         p++;
  226.     if (*p != ':')
  227.         return NOHEADER;
  228.   
  229.     for (i = 0; Hdrs[i] != NULLCHAR; i++) {
  230.         if (strnicmp(Hdrs[i],s,strlen(Hdrs[i])) == 0)
  231.             return i;
  232.     }
  233.     return UNKNOWN;
  234. }
  235.   
  236. int get_index(int msg,char *name,struct mailindex *ind) {
  237.     int idx;
  238.     struct indexhdr hdr;
  239.     char buf[FILE_PATH_SIZE];
  240.   
  241.     sprintf(buf,"%s/%s.ind",Mailspool,name);
  242.     if((idx=open(buf,READBINARY)) == -1) {
  243.         return -1;
  244.     }
  245.   
  246.     if((read_header(idx,&hdr) == 0) && (msg <= hdr.msgs)) {
  247.         while(msg--) {
  248.             default_index(name,ind);
  249.             read_index(idx,ind);
  250.         }
  251.         close(idx);
  252.         return 0;
  253.     }
  254.     close(idx);
  255.     return -1;
  256. }
  257.   
  258. void set_index(char *buf,struct mailindex *index) {
  259.     char *s,*cp;
  260.     struct cclist *cc;
  261.     struct fwdbbs *bbs;
  262.     struct tm t;
  263.   
  264.     switch(htype(buf)) {
  265.         case APPARTO:
  266.             if(index->to)
  267.                 break;
  268.         /* Notice fall-through */
  269.         case TO:
  270.             free(index->to);
  271.             index->to = strdup(getaddress(buf,0));
  272.             break;
  273.         case STATUS:
  274.             if(buf[8] == 'R')
  275.                 index->status |= BM_READ;
  276.             break;
  277.         case XBBSHOLD:
  278.             index->status |= BM_HOLD;
  279.             break;
  280.         case FROM:
  281.             free(index->from);
  282.             index->from = strdup(getaddress(buf,0));
  283.             break;
  284.         case REPLYTO:
  285.             free(index->replyto);
  286.             index->replyto = strdup(getaddress(buf,0));
  287.             break;
  288.         case SUBJECT:
  289.             free(index->subject);
  290.             index->subject = strdup(&buf[9]);
  291.         /* translate possible left over cr/lf's to spaces */
  292.             cp = index->subject;
  293.             while(*cp) {
  294.                 if(*cp == '\n' || *cp == 0xd){
  295.                     *cp = '\0';
  296.                     break;
  297.                 }
  298.                 cp++;
  299.             }
  300.             break;
  301.         case BBSTYPE:
  302.             index->type = buf[16];
  303.             break;
  304.         case MSGID:
  305.             free(index->messageid);
  306.             index->messageid = strdup(getaddress(buf,0));
  307.             break;
  308.         case XFORWARD:
  309.             bbs = mallocw(sizeof(struct fwdbbs));
  310.             strcpy(bbs->call,&buf[16]);
  311.             bbs->next = index->bbslist;
  312.             index->bbslist = bbs;
  313.             break;
  314.         case CC:
  315.             s = &buf[4];
  316.             while(*s) {
  317.                 if((cp=strchr(s,','))!=NULL){
  318.                     *cp = '\0';
  319.                 } else
  320.                     cp = s + strlen(s) - 1;
  321.                 while(*s == ' ' || *s == '\t')
  322.                     s++;
  323.                 cc = mallocw(sizeof(struct cclist));
  324.                 cc->to = strdup(s);
  325.                 cc->next = index->cclist;
  326.                 index->cclist = cc;
  327.                 s = cp + 1;
  328.             }
  329.             break;
  330.         case DATE:
  331.         /* find age from ARPA style date */
  332.             index->date = mydate(&buf[6]);
  333.             break;
  334.     } /* switch */
  335. }
  336.   
  337. /* Update the index file */
  338. int WriteIndex(int idx, struct mailindex *ind) {
  339.     long startoffset,length;
  340.     int len, xlen;
  341.     struct indexhdr hdr;
  342.     struct fwdbbs *bbs;
  343.     struct cclist *cc;
  344.     char null = '\0';
  345.   
  346.     if ((startoffset = lseek(idx,0,SEEK_CUR)) == -1L) return -1;
  347.   
  348.     /* write length bytes */
  349.     write(idx,&len,sizeof(len));
  350.   
  351.     /* write message id */
  352.     write(idx,&ind->msgid,sizeof(ind->msgid));
  353.     xlen = sizeof(ind->msgid);
  354.   
  355.     /* write message type */
  356.     write(idx,&ind->type,sizeof(ind->type));
  357.     xlen += sizeof(ind->type);
  358.   
  359.     /* write message status */
  360.     write(idx,&ind->status,sizeof(ind->status));
  361.     xlen += sizeof(ind->status);
  362.   
  363.     /* write message size */
  364.     write(idx,&ind->size,sizeof(ind->size));
  365.     xlen += sizeof(ind->size);
  366.   
  367.     /* write to-address */
  368.     if(ind->to) {
  369.         write(idx,ind->to,strlen(ind->to));
  370.         xlen += strlen(ind->to);
  371.     }
  372.     write(idx,&null,sizeof(null));
  373.     xlen += sizeof(null);
  374.   
  375.     /* write from-address */
  376.     if(ind->from){
  377.         write(idx,ind->from,strlen(ind->from));
  378.         xlen += strlen(ind->from);
  379.     }
  380.     write(idx,&null,sizeof(null));
  381.     xlen += sizeof(null);
  382.   
  383.     /* write subject field */
  384.     if(ind->subject){
  385.         write(idx,ind->subject,strlen(ind->subject));
  386.         xlen += strlen(ind->subject);
  387.     }
  388.     write(idx,&null,sizeof(null));
  389.     xlen += sizeof(null);
  390.   
  391.     /* write reply-to field */
  392.     if(ind->replyto){
  393.         write(idx,ind->replyto,strlen(ind->replyto));
  394.         xlen += strlen(ind->replyto);
  395.     }
  396.     write(idx,&null,sizeof(null));
  397.     xlen += sizeof(null);
  398.   
  399.     /* write message-id field */
  400.     if(ind->messageid){
  401.         write(idx,ind->messageid,strlen(ind->messageid));
  402.         xlen += strlen(ind->messageid);
  403.     }
  404.     write(idx,&null,sizeof(null));
  405.     xlen += sizeof(null);
  406.   
  407.     /* write received date */
  408.     write(idx,&ind->mydate,sizeof(ind->mydate));
  409.     xlen += sizeof(ind->mydate);
  410.   
  411.     /* write date */
  412.     write(idx,&ind->date,sizeof(ind->date));
  413.     xlen += sizeof(ind->date);
  414.   
  415.     /* write all Cc addressees */
  416.     for(cc=ind->cclist;cc;cc=cc->next){
  417.         write(idx,cc->to,strlen(cc->to)+1);
  418.         xlen += strlen(cc->to)+1;
  419.     }
  420.     write(idx,&null,sizeof(null));
  421.     xlen += sizeof(null);
  422.   
  423.     /* write all forwarded bbs's */
  424.     for(bbs=ind->bbslist;bbs;bbs = bbs->next){
  425.         write(idx,bbs->call,strlen(bbs->call)+1);
  426.         xlen += strlen(bbs->call)+1;
  427.     }
  428.     /* terminate with null character */
  429.     write(idx,&null,sizeof(null));
  430.     xlen += sizeof(null);
  431.   
  432.     /* Now update the length */
  433.     len = (int) (lseek(idx,0,SEEK_CUR) - startoffset - sizeof(len));
  434.     lseek(idx,startoffset,SEEK_SET);    /* regain start pos */
  435.     if (len != xlen) {        /* serious write or seek error */
  436.         write(idx, &null, 0);    /* truncate index */
  437.         return -1;
  438.     }
  439.         
  440.     if (write(idx,&len,sizeof(len)) != sizeof(len)) return -1;
  441.   
  442.     /* Now update the number of records */
  443.     if (read_header(idx,&hdr) == 0) {
  444.         hdr.msgs++;
  445.         if(!(ind->status & BM_HOLD+BM_READ))
  446.             hdr.unread++;
  447.         xlen=write_header(idx,&hdr);
  448.     }
  449.     else xlen = -1;
  450.   
  451.     /* Go to end of file again */
  452.     lseek(idx,0,SEEK_END);
  453.   
  454.     return xlen;
  455. }
  456.   
  457. void default_header(struct indexhdr *hdr) {
  458.     hdr->msgs = 0;
  459.     hdr->unread = 0;
  460. }
  461.   
  462. void default_index(char *name, struct mailindex *ind) {
  463.     struct fwdbbs *cbbs,*nbbs;
  464.     struct cclist *cc,*ncc;
  465.   
  466.     ind->msgid = 0;
  467.   
  468. #ifdef MAILCMDS
  469. #ifdef MAILBOX
  470.     if(isarea(name))
  471.         ind->type = 'B';
  472.     else
  473. #endif
  474. #endif
  475.         ind->type = 'P';
  476.   
  477.     ind->status = 0;
  478.   
  479.     ind->size = 0;
  480.   
  481.     free(ind->to);
  482.     ind->to = NULL;
  483.   
  484.     free(ind->from);
  485.     ind->from = NULL;
  486.   
  487.     free(ind->subject);
  488.     ind->subject = NULL;
  489.   
  490.     free(ind->replyto);
  491.     ind->replyto = NULL;
  492.   
  493.     free(ind->messageid);
  494.     ind->messageid = NULL;
  495.   
  496.     ind->mydate = 0;
  497.     ind->date = 0;
  498.   
  499.     for(cbbs = ind->bbslist;cbbs;cbbs = nbbs) {
  500.         nbbs = cbbs->next;
  501.         free(cbbs);
  502.     }
  503.     ind->bbslist = NULL;
  504.   
  505.     for(cc = ind->cclist;cc;cc = ncc) {
  506.         ncc = cc->next;
  507.         free(cc->to);
  508.         free(cc);
  509.     }
  510.     ind->cclist = NULL;
  511.   
  512. }
  513.   
  514. long mydate(char *s) {
  515.     struct tm t;
  516.     char *cp;
  517.   
  518.     while(*s == ' ')
  519.         s++;
  520.     /* check to see if there is a "Day, " field */
  521.     if((cp=strchr(s,',')) != NULL)  {
  522.         /* probably standard ARPA style header */
  523.         cp += 2; /* get past header and DAY field */
  524.     } else {
  525.         /* probably a NNTP style message, that has no
  526.          * "Day, " part in the date line
  527.          */
  528.         cp = s;
  529.     }
  530.   
  531.     while(*cp == ' ')
  532.         cp++;
  533.     /* now we should be at the start of the
  534.      * "14 Apr 92 08:14:32" string
  535.      */
  536.     if(strlen(cp) < 17)
  537.         return 0;
  538.     t.tm_mday = atoi(cp);
  539.     /* Find month */
  540.     while(*cp != ' ')
  541.         ++cp;
  542.     while(*cp == ' ')
  543.         ++cp;
  544.     for(t.tm_mon=0; t.tm_mon < 12; t.tm_mon++)
  545.         if(strnicmp(Months[t.tm_mon],cp,3) == 0)
  546.             break;
  547.     if(t.tm_mon == 12)
  548.         return 0; /* invalid */
  549.     t.tm_year = atoi(cp+4);
  550.     /* Modification by VE4WTS for 4-character year string */
  551.     if(t.tm_year>100) {
  552.         t.tm_year=t.tm_year%100;
  553.         t.tm_hour=atoi(cp+9);
  554.         t.tm_min=atoi(cp+12);
  555.         t.tm_sec=atoi(cp+15);
  556.     } else {
  557.         t.tm_hour = atoi(cp+7);
  558.         t.tm_min = atoi(cp+10);
  559.         t.tm_sec = atoi(cp+13);
  560.     }
  561.     /*
  562.     tprintf("DATE: %d %d %d, %d %d %d\n",
  563.             t.tm_mday,t.tm_mon,t.tm_year,t.tm_hour,t.tm_min,t.tm_sec);
  564.     */
  565.     return mktime(&t);
  566.   
  567. }
  568.   
  569. /* Read a file containing messages,
  570.  * and build the index file from scratch from the smtp headers.
  571.  * Parameters:
  572.  *    char *name should be the full area filename in dir format,
  573.  *       without ending '.txt' ! Eg: '/spool/mail/johan'
  574.  *    int verbose ; if set, the index is printed before written
  575.  */
  576. int IndexFile(char *name,int verbose) {
  577.     FILE *fp;
  578.     int header,previous;
  579.     long start,pos;
  580.     char *cp;
  581.     int idx;
  582.     struct indexhdr hdr;
  583.     struct mailindex ind;
  584.     char buf[FILE_PATH_SIZE];
  585.   
  586.     sprintf(buf,"%s/%s.txt",Mailspool,name);
  587.     if((fp = fopen(buf,READ_BINARY)) == NULL)
  588.         return NOMBX;
  589.   
  590.     /* Create new index file */
  591.     sprintf(buf,"%s/%s.ind",Mailspool,name);
  592.     if((idx = open(buf,CREATETRUNCATEBINARY,CREATEMODE)) == -1) {
  593.         fclose(fp);
  594.         return NOIND;
  595.     }
  596.     /* set number of msgs to 0 */
  597.     default_header(&hdr);
  598.     if (write_header(idx,&hdr) == -1) return ERROR;
  599.   
  600.     start = pos = 0;
  601.     previous = 0;
  602.     memset(&ind,0,sizeof(ind));
  603.     default_index(name,&ind);
  604.   
  605.     while(bgets(buf, sizeof(buf), fp) != NULL) {
  606.         pwait(NULL);    /* Be nice to others :-) */
  607.         /* search 'From ' line */
  608.         if(!strncmp(buf,"From ",5)) {
  609.             /* Start of next message */
  610.             if(previous) {
  611.                 /* Write index for previous message */
  612.                 ind.size = pos - start;
  613.                 if(verbose)
  614.                     print_index(&ind);
  615.                 if(WriteIndex(idx,&ind) == -1) {
  616.                     default_index("",&ind);
  617.                     fclose(fp);
  618.                     close(idx);
  619.                     return ERROR;
  620.                 }
  621.             } else
  622.                 previous = 1;
  623.   
  624.             /* Clear the index for this message */
  625.             default_index(name,&ind);
  626.             start = pos;
  627.   
  628.             /* Read the 'Received...' and 'ID... lines'
  629.              * to get the msgid - WG7J
  630.              */
  631.             if(bgets(buf, sizeof(buf), fp) == NULL) {   /* "Received " line */
  632.                 default_index("",&ind);
  633.                 fclose(fp);
  634.                 close(idx);
  635.                 return ERROR;
  636.             }
  637.             if(bgets(buf, sizeof(buf), fp) == NULL) {   /* 'id' line */
  638.                 default_index("",&ind);
  639.                 fclose(fp);
  640.                 close(idx);
  641.                 return ERROR;
  642.             }
  643.             if((cp=strstr(buf,"AA")) != NULL)
  644.                 /* what follows is the message-number */
  645.                 ind.msgid = atol(cp+2);
  646.             if((cp=strchr(buf,';')) != NULL)
  647.                 ind.mydate = mydate(cp+2);
  648.             header = 1;
  649.             pos = ftell(fp);
  650.             /* While in the SMTP header, set index fields */
  651.             while(bgets(buf,sizeof(buf),fp) != NULLCHAR ) {
  652.                 if(*buf == '\0')
  653.                     break;
  654.                 set_index(buf,&ind);
  655.             }
  656.         }
  657.         pos = ftell(fp);
  658.     }
  659.     if(ferror(fp)) {
  660.         default_index("",&ind);
  661.         fclose(fp);
  662.         close(idx);
  663.         return ERROR;
  664.     }
  665.     if(previous) {
  666.         ind.size = pos - start;
  667.         if(verbose)
  668.             print_index(&ind);
  669.         if(WriteIndex(idx,&ind) == -1) {/* Write index for previous message */
  670.             default_index("",&ind);
  671.             fclose(fp);
  672.             close(idx);
  673.             return ERROR;
  674.         }
  675.     }
  676.     default_index("",&ind);
  677.     fclose(fp);
  678.     close(idx);
  679.     return 0;
  680. }
  681.   
  682. /* Update the index file */
  683. int write_index(char *name, struct mailindex *ind) {
  684.     int idx, err;
  685.     struct indexhdr hdr;
  686.     char buf[FILE_PATH_SIZE];
  687.   
  688.     sprintf(buf,"%s/%s.ind",Mailspool,name);
  689.     if((idx=open(buf,READWRITEBINARY)) == -1) {
  690.         /* Index file doesn't exist, create it */
  691.         if((idx=open(buf,CREATETRUNCATEBINARY,CREATEMODE)) != -1){
  692.             default_header(&hdr);
  693.             if (write_header(idx,&hdr) == -1) return -1;
  694.         } else
  695.             return -1;
  696.     }
  697.     lseek(idx,0,SEEK_END);
  698.     err=WriteIndex(idx,ind);
  699.     close(idx);
  700.     return err;
  701. }
  702.   
  703. void delete_index(char *filename) {
  704.     char idxfile[FILE_PATH_SIZE];
  705.   
  706.     sprintf(idxfile,"%s/%s.ind",Mailspool,filename);
  707.     unlink(idxfile);
  708. }
  709.   
  710. int write_header(int idx,struct indexhdr *hdr) {
  711.   
  712.     lseek(idx,0,SEEK_SET);
  713.     hdr->version = INDEXVERSION;
  714.     return (write(idx,hdr,sizeof(struct indexhdr)) == sizeof(struct indexhdr) ? 0 : -1);
  715. }
  716.   
  717. int read_header(int idx,struct indexhdr *hdr) {
  718.     int val;
  719.   
  720.     lseek(idx,0,SEEK_SET);
  721.     val = read(idx,hdr,sizeof(struct indexhdr));
  722.     if(val != sizeof(struct indexhdr) || hdr->version != INDEXVERSION)
  723.         return -1;
  724.     return 0;
  725. }
  726.   
  727. /* Read an index from the index file. Assumes the file is opened
  728.  * for binary reads, and that the filepointer is pointing to the
  729.  * start of the message to read...
  730.  * Returns 0 if valid, -1 if error
  731.  */
  732. int read_index(int idx,struct mailindex *ind) {
  733.     int len;
  734.     char *buf,*curr;
  735.     struct cclist *newcc;
  736.     struct fwdbbs *newbbs;
  737.   
  738.     /* Get the size of this index */
  739.     if(read(idx,&len,sizeof(len)) != sizeof(len))
  740.         return -1;
  741.   
  742.     /* Now read the index */
  743.     if((buf = mallocw(len)) == NULL)
  744.         return -1;
  745.   
  746.     if(read(idx,buf,len) != len) {
  747.         free(buf);
  748.         return -1;
  749.     }
  750.   
  751.     /* And copy all elements to the index */
  752.     curr = buf;
  753.   
  754.     /* Get the message id */
  755.     ind->msgid = *(long *)curr;
  756.     curr += sizeof(ind->msgid);
  757.   
  758.     ind->type = *curr++;
  759.     ind->status = *curr++;
  760.   
  761.     ind->size = *(long*)curr;
  762.     curr += sizeof(ind->size);
  763.   
  764.     ind->to = strdup(curr);
  765.     curr += strlen(curr) + 1;
  766.   
  767.     ind->from = strdup(curr);
  768.     curr += strlen(curr) + 1;
  769.   
  770.     ind->subject = strdup(curr);
  771.     curr += strlen(curr) + 1;
  772.   
  773.     ind->replyto = strdup(curr);
  774.     curr += strlen(curr) + 1;
  775.   
  776.     ind->messageid = strdup(curr);
  777.     curr += strlen(curr) + 1;
  778.   
  779.     ind->mydate = *(long *)curr;
  780.     curr += sizeof(ind->mydate);
  781.   
  782.     ind->date = *(long *)curr;
  783.     curr += sizeof(ind->date);
  784.   
  785.     while(*curr) {
  786.         newcc = mallocw(sizeof(struct cclist));
  787.         newcc->to = strdup(curr);
  788.         newcc->next = ind->cclist;
  789.         ind->cclist = newcc;
  790.         curr += strlen(curr) + 1;
  791.     }
  792.     curr++;
  793.   
  794.     while(*curr) {
  795.         newbbs = mallocw(sizeof(struct fwdbbs));
  796.         strcpy(newbbs->call,curr);
  797.         newbbs->next = ind->bbslist;
  798.         ind->bbslist = newbbs;
  799.         curr += strlen(curr) + 1;
  800.     }
  801.   
  802.     free(buf);
  803.     return 0;
  804.   
  805. };
  806.   
  807. void print_index(struct mailindex *ind) {
  808.     struct fwdbbs *bbs;
  809.     struct cclist *cc;
  810.   
  811.     tprintf("\nSize %ld, ID %ld, flags: %c%c%c\n",ind->size,ind->msgid,ind->type,
  812.     ind->status & BM_READ ? 'R' : 'N',ind->status & BM_HOLD ? 'H' : ' ');
  813.     tprintf("To: %s\n",ind->to);
  814.     tprintf("Cc:");
  815.     for(cc=ind->cclist;cc;cc=cc->next)
  816.         tprintf(" %s",cc->to);
  817.     tputc('\n');
  818.     tprintf("From: %s\n",ind->from);
  819.     tprintf("Received: %s",ctime(&ind->mydate));
  820.     tprintf("Reply-to: %s\n",ind->replyto ? ind->replyto : "");
  821.     tprintf("Subject: %s\n",ind->subject);
  822.     tprintf("Message-Id: %s\n",ind->messageid);
  823.     tprintf("Date: %s",ctime(&ind->date));
  824.     tprintf("X-Forwarded-To:");
  825.     for(bbs=ind->bbslist;bbs;bbs=bbs->next)
  826.         tprintf(" %s",bbs->call);
  827.     tputc('\n');
  828.     tputc('\n');
  829. }
  830.   
  831.   
  832. void dotformat(char *area) {
  833.   
  834.     while(*area) {
  835.         if(*area == '\\' || *area == '/')
  836.             *area = '.';
  837.         area++;
  838.     }
  839. }
  840.   
  841. void dirformat(char *area) {
  842.   
  843.     while(*area) {
  844.         if(*area == '\\' || *area == '.')
  845.             *area = '/';
  846.         area++;
  847.     }
  848. }
  849.   
  850. void firsttoken(char *line) {
  851.   
  852.     while(*line) {
  853.         if(*line == ' ' || *line == '\n' || *line == '\t') {
  854.             *line = '\0';
  855.             break;
  856.         }
  857.         line++;
  858.     }
  859. }
  860.   
  861. /* Returns 1 if name is a public message Area, 0 otherwise */
  862. int
  863. isarea(name)
  864. char *name;
  865. {
  866.     FILE *fp;
  867.     char *cp, *area;
  868.     char buf[LINELEN];
  869.   
  870.     if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
  871.         return 0;
  872.     area = strdup(name);
  873.     dotformat(area);
  874.     while(fgets(buf,sizeof(buf),fp) != NULLCHAR) {
  875.         /* The first word on each line is all that matters */
  876.         firsttoken(buf);
  877.         dotformat(buf);
  878.         if(stricmp(area,buf) == 0) {    /* found it */
  879.             fclose(fp);
  880.             free(area);
  881.             return 1;
  882.         }
  883.     }
  884.     fclose(fp);
  885.     free(area);
  886.     return 0;
  887. }
  888.   
  889. /* Get a line from the text file that was opened in binary mode.
  890.  * Delete the CR/LF at the end !
  891.  */
  892. char *bgets(char * buf,int size,FILE *fp) {
  893.     char *cp;
  894.   
  895.     if(fgets(buf,size,fp) == NULL)
  896.         return NULL;
  897.     cp = buf;
  898.     while(*cp) {
  899.         if(*cp == 0xd || *cp == 0xa)
  900.             *cp = '\0';
  901.         cp++;
  902.     }
  903.     return buf;
  904. }
  905.   
  906. #ifdef notdef
  907. void readareas __ARGS((char *name,char *mpath));
  908. int is_area __ARGS((char *name));
  909. int isarea;
  910.   
  911. struct areas {
  912.     struct areas *next;
  913.     char *name;
  914. };
  915. struct areas *Areas = NULL;
  916.   
  917. void readareas(char *name,char *mpath) {
  918.     FILE *fp;
  919.     struct areas *ca,*na;
  920.     char *cp,mp[FILE_PATH_SIZE],buf[FILE_PATH_SIZE];
  921.   
  922.     if((fp=fopen(name,READ_TEXT)) == NULL)
  923.         return;
  924.   
  925.     while(fgets(buf,sizeof(buf),fp) != NULL) {
  926.         if(buf[0] == '#')   /* comment line */
  927.             continue;
  928.         cp = buf;
  929.         /* get first token on line */
  930.         while(*cp) {
  931.             if(*cp == '\n' || *cp == ' ' || *cp == '\t') {
  932.                 *cp = '\0';
  933.                 break;
  934.             }
  935.             cp++;
  936.         }
  937.         if(buf[0] != '\0') {
  938.             cp = buf;
  939.             while(*cp) {
  940.                 if(*cp == '.' || *cp == '\\')
  941.                     *cp = '/';
  942.                 cp++;
  943.             }
  944.             sprintf(mp,"%s/%s.txt",mpath,buf);
  945.             na = malloc(sizeof(struct areas));
  946.             na->name = strdup(mp);
  947.             na->next = NULL;
  948.             if(Areas == NULL) {
  949.                 Areas = na;
  950.             } else {
  951.                 ca->next = na;
  952.             }
  953.             ca = na;
  954.         }
  955.     }
  956.     fclose(fp);
  957. }
  958.   
  959. int is_area(char *name) {
  960.     struct areas *a;
  961.   
  962.     a = Areas;
  963.     while(a) {
  964.         if(stricmp(a->name,name) == 0)
  965.             return 1;
  966.         a = a->next;
  967.     }
  968.     return 0;
  969. }
  970.   
  971. void showareas() {
  972.     struct areas *a;
  973.   
  974.     a = Areas;
  975.     while(a) {
  976.         tprintf("%s\n",a->name);
  977.         a = a->next;
  978.     }
  979. }
  980. #endif
  981.   
  982. #ifndef MAIL2IND
  983.   
  984. void UpdateIndex(char *path,int force) {
  985.     char *wildcard,*newpath,*fullname;
  986.     struct ffblk ff,iff;
  987.     int done;
  988.   
  989.     if((wildcard = malloc(129)) == NULL) {
  990.         return;
  991.     }
  992.     if((newpath = malloc(129)) == NULL) {
  993.         free(wildcard);
  994.         return;
  995.     }
  996.     if((fullname = malloc(129)) == NULL) {
  997.         free(wildcard);
  998.         free(newpath);
  999.         return;
  1000.     }
  1001.   
  1002.     /* First check all the files */
  1003.     if(!path)
  1004.         sprintf(wildcard,"%s/*.txt",Mailspool);
  1005.     else
  1006.         sprintf(wildcard,"%s/%s/*.txt",Mailspool,path);
  1007.     done = findfirst(wildcard,&ff,0);
  1008.     while(!done){
  1009.         if(!path)
  1010.             strcpy(fullname,ff.ff_name);
  1011.         else
  1012.             sprintf(fullname,"%s/%s",path,ff.ff_name);
  1013.   
  1014.         /* get rid of extension */
  1015.         *(fullname+strlen(fullname)-4) = '\0';
  1016.         if(force) {
  1017.             /* Attempt to lock the mail file! */
  1018.             if(!mlock(Mailspool,fullname)) {
  1019.                 IndexFile(fullname,0);
  1020.                 rmlock(Mailspool,fullname);
  1021.             }
  1022.         } else {
  1023.             /* Now find the index file */
  1024.             sprintf(wildcard,"%s/%s",Mailspool,fullname);
  1025.             strcat(wildcard,".IND");
  1026.             /* If there is no index, or the index is older then the text file.
  1027.              * Go create a new index file !
  1028.              */
  1029.             if( findfirst(wildcard,&iff,0) != 0 ||
  1030.                 (ff.ff_fdate > iff.ff_fdate) ||
  1031.                 ((ff.ff_fdate == iff.ff_fdate) && ff.ff_ftime > iff.ff_ftime)
  1032.             ) {
  1033.                 /* Attempt to lock the mail file! */
  1034.                 if(!mlock(Mailspool,fullname)) {
  1035.                     IndexFile(fullname,0);
  1036.                     rmlock(Mailspool,fullname);
  1037.                 }
  1038.             }
  1039.         }
  1040.         done = findnext(&ff);
  1041.     }
  1042.     /* Now check for sub-directories */
  1043.     if(!path)
  1044.         sprintf(wildcard,"%s/*.*",Mailspool);
  1045.     else
  1046.         sprintf(wildcard,"%s/%s/*.*",Mailspool,path);
  1047.     done = findfirst(wildcard,&ff,FA_DIREC);
  1048.     while(!done){
  1049.         if(strcmp(ff.ff_name,".") && strcmp(ff.ff_name,"..")) {
  1050.             /* Not the present or 'mother' directory, so create new path,
  1051.              * and recurs into it.
  1052.              */
  1053.             if(!path)
  1054.                 strcpy(newpath,ff.ff_name);
  1055.             else
  1056.                 sprintf(newpath,"%s/%s",path,ff.ff_name);
  1057.             UpdateIndex(newpath,force);
  1058.         }
  1059.         done = findnext(&ff);
  1060.     }
  1061.     free(wildcard);
  1062.     free(newpath);
  1063.     free(fullname);
  1064.     return;
  1065. }
  1066.   
  1067. /* Make sure the index file associated with the mailbox 'name' is current.
  1068.  * The mailbox should be locked before calling SyncIndex.
  1069.  * Parameters:
  1070.  *    char *name should be the area filename, without ending '.txt' !
  1071.  *   Eg: 'johan'
  1072.  * Returns:
  1073.  *  NOERROR (== 0) if index was current, or has been made current.
  1074.  *  others if unable to update the index file.
  1075.  */
  1076. int SyncIndex(char *name)
  1077. {
  1078.     int mail,ind;
  1079.     struct ffblk mff,iff;
  1080.     char *area;
  1081.     char buf[129];
  1082.   
  1083.     area = strdup(name);    /* ensure mbox name is in dir format */
  1084.     dirformat(area);
  1085.   
  1086.     /* Check the index file */
  1087.     sprintf(buf,"%s/%s.txt",Mailspool,area);
  1088.     mail = findfirst(buf,&mff,0);
  1089.   
  1090.     sprintf(buf,"%s/%s.ind",Mailspool,area);
  1091.     ind = findfirst(buf,&iff,0);
  1092.   
  1093.     if(mail != 0 && ind == 0) {
  1094.         ind=unlink(buf);    /* remove index file if mbox nonexistent */
  1095.     }
  1096.     else if((mail == 0 && ind != 0) ||
  1097.         (mff.ff_fdate > iff.ff_fdate) ||
  1098.         ((mff.ff_fdate == iff.ff_fdate) && mff.ff_ftime > iff.ff_ftime)
  1099.     ) {
  1100.         ind=IndexFile(area,0);
  1101.     }
  1102.     else ind=NOERROR;
  1103.   
  1104.     free(area);
  1105.     return(ind);
  1106. }
  1107.   
  1108. #endif /* MAIL2IND */
  1109.   
  1110.